package com.runa.rccprotocol.dto.runa;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.comm.dto.Node;
import com.runa.monitor.comm.dto.RunaEquArchive;
import com.runa.persistence.CollectionUtil;
import com.runa.protocol.dto.IResponseData;
import com.runa.protocol.enums.ByteOrder;
import com.runa.protocol.util.ByteUtil;
import com.runa.protocol.util.UtilTime;
import com.runa.rccprotocol.constant.AppFunCode;
import com.runa.rccprotocol.dto.ConcentratorRequestData;
import com.runa.rccprotocol.dto.equdata.TerminalCalendarClock;
import com.runa.rccprotocol.dto.hanyang.HyMeterRequestData;
import com.runa.rccprotocol.dto.kute.KtValveRequestData;
import com.runa.rccprotocol.dto.param.*;
import com.runa.rccprotocol.dto.pusai.PsValveRequestData;
import com.runa.rccprotocol.dto.wukexing.WkxValveRequestData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 瑞纳智能集中器协议对照请求（按文档排列）
 *
 * @author zhuj
 */
@Slf4j
public class RunaConcenRequestData extends ConcentratorRequestData {

    private RunaICStruct struct;
    private List<Integer> pns;

    public RunaConcenRequestData(String address) {
        super(address);
    }

    public List<Integer> getPns() {
        return pns;
    }

    public void setPns(List<Integer> pns) {
        this.pns = pns;
    }

    public void resetCommand(int fn) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM0_UserData));
        struct.setAfn(AppFunCode.rnicAFN.Reset);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, fn, new byte[16]));

        setHaveResult(true);
    }

    /* ------------------- 设置参数 ------------------ */

    /**
     * 设置GPRS主站
     *
     * @param ipPort
     */
    public void GPRSIpPort(GPRSIpPort ipPort) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ReqTerminalConfig);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        byte[] bytes = new byte[28];
        int i = 0;
        for (String ip : ipPort.getIp1().split("\\.")) {
            bytes[i++] = (byte) Integer.parseInt(ip);
        }
        ByteUtil.shortToByte((short) ipPort.getPort1(), bytes, i, ByteOrder.BA);
        i += 2;
        for (String ip : ipPort.getIp2().split("\\.")) {
            bytes[i++] = (byte) Integer.parseInt(ip);
        }
        ByteUtil.shortToByte((short) ipPort.getPort2(), bytes, i, ByteOrder.BA);
        i += 2;
        if (ipPort.getAPN() != null) {
            byte[] apn = ipPort.getAPN().getBytes();
            for (int ii = 0; i < bytes.length; i++, ii++) {
                bytes[i] = apn[ii];
            }
        }
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 3, bytes));

        setHaveResult(false);
    }

    /**
     * 设置供暖季
     *
     * @param season
     */
    public void heatingSeason(HeatingSeason season) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.SetParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        byte[] bytes = new byte[4];
        ByteUtil.intToBcd(bytes, 0, season.getStartDay(), true);
        ByteUtil.intToBcd(bytes, 1, season.getStartMonth(), true);
        ByteUtil.intToBcd(bytes, 2, season.getEndDay(), true);
        ByteUtil.intToBcd(bytes, 3, season.getEndMonth(), true);
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 100, bytes));

        setHaveResult(false);
    }

    /**
     * 设置集中器测点档案
     *
     * @param records
     */
    public void setParameter(List<IndexRecord> records) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.SetParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        byte[][] bytes = new byte[records.size()][];
        for (int i = 0; i < records.size(); i++) {
            bytes[i] = records.get(i).getBytes();
        }
        byte[] countBs = new byte[]{(byte) bytes.length, (byte) (bytes.length << 8)};
        struct.addDataField(new RunaFrameSequence.DataUnit(
                0, 91, ByteUtil.merge(countBs, ByteUtil.merge(bytes))));

        setHaveResult(true);
    }

    /**
     * 公建节能单元时段方案控制（方案时段+周模式日方案+自定义节假日）
     *
     * @param pn
     * @param strategy
     * @param schemes
     * @param select
     * @param schemeSelect
     */
    public void sentTimeFrameControl(int pn, PublicUnitAdjustStrategy strategy, List<Map<String, Float>> schemes,
                                     PublicUnitWeekDaySchemeSelect select, PublicUnitDiyHolidaySchemeSelect schemeSelect) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.SetParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        byte[] bs;

        //4.单元调控策略
        bs = new byte[6];
        bs[0] = (byte) strategy.getHandAuto();
        bs[1] = (byte) strategy.getControlObject();
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 216, bs));

        //1.方案时段温度值
        bs = new byte[1 + 37 * schemes.size()];
        bs[0] = (byte) schemes.size();
        int value, hour, minute, index = 0, count = 1;
        for (Map<String, Float> scheme : schemes) {
            bs[1 + index] = (byte) count;
            int start = index;
            for (Map.Entry<String, Float> entry : scheme.entrySet()) {
                String[] time = entry.getKey().split(":");
                value = (int) (entry.getValue() * 100);
                hour = Integer.parseInt(time[0]);
                minute = Integer.parseInt(time[1]);
                bs[2 + start] = (byte) (minute % 10 + ((minute / 10 % 10) << 4));
                bs[3 + start] = (byte) (hour % 10 + ((hour / 10 % 10) << 4));
                ByteUtil.intToBcd(bs, 4 + start, value, true);
                start += 6;
            }
            index += 37;
            count++;
        }
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 210, bs));

        //2.周模式日方案选择
        bs = new byte[7];
        bs[0] = (byte) select.getMonday();
        bs[1] = (byte) select.getTuesday();
        bs[2] = (byte) select.getWednesday();
        bs[3] = (byte) select.getThursday();
        bs[4] = (byte) select.getFriday();
        bs[5] = (byte) select.getSaturday();
        bs[6] = (byte) select.getSunday();
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 211, bs));

        //3.自定义节假日时段方案选择
        bs = new byte[1 + 8 * schemeSelect.getCount()];
        bs[0] = (byte) schemeSelect.getCount();
        String time;
        index = 0;
        for (PublicUnitDiyHolidaySchemeSelect.SchemeSelect select0 : schemeSelect.getSchemeSelects()) {
            bs[1 + index] = (byte) select0.index;
            time = select0.startTime.replaceAll("-", "");
            ByteUtil.intToBcd(bs, 2 + index, Integer.parseInt(time), true);
            time = select0.endTime.replaceAll("-", "");
            ByteUtil.intToBcd(bs, 5 + index, Integer.parseInt(time), true);
            bs[8 + index] = (byte) select0.schemeNo;
            index += 8;
        }
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 212, bs));

        setHaveResult(true);
    }

    /**
     * PID
     *
     * @param pn
     * @param pid
     */
    public void sentPidParameter(int pn, PID pid) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.SetParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 213, new byte[]{pid.getP(), pid.getI(), pid.getD()}));

        setHaveResult(true);
    }

    /**
     * 开度限值
     *
     * @param pn
     * @param limit
     */
    public void sentPuolParameter(int pn, PublicUnitOpeningLimit limit) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.SetParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 215,
                new byte[]{(byte) limit.getDownLimit(), (byte) limit.getUpLimit()}));

        setHaveResult(true);
    }

    /**
     * 单元调控策略
     *
     * @param pn
     * @param strategy
     */
    public void sentPuasParameter(int pn, PublicUnitAdjustStrategy strategy) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.SetParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        byte[] bs = new byte[6];
        bs[0] = (byte) strategy.getHandAuto();
        bs[1] = (byte) strategy.getControlObject();
        ByteUtil.intToBcd(bs, 2, (int) (strategy.getSetting() * 100), true);
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 216, bs));

        setHaveResult(true);
    }

    /**
     * 抄表周期
     *
     * @param meterReadingCycle
     */
    public void sentMeterReadingCycleParameter(MeterReadingCycle meterReadingCycle) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.SetParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 191, meterReadingCycle.toBytes()));
        setHaveResult(true);
    }

    /**
     * 设置拓展参数
     *
     * @param param
     */
    public void sentExtendParam(ExtendParam param) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.SetParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 0, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 248, param.toBuffer()));

        setHaveResult(true);
    }

    /**
     * 读取集中器测点档案
     */
    public void readParameter(List<Integer> pns) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        int count = pns.size();
        byte[] bs = new byte[2 + count * 2];
        bs[0] = (byte) count;
        bs[1] = (byte) (count >> 8);
        for (int i = 0; i < count; i++) {
            bs[2 + 2 * i] = pns.get(i).byteValue();
            bs[3 + 2 * i] = (byte) (pns.get(i) >> 8);
        }
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 91, bs));

        setHaveResult(true);
    }

    /**
     * 读方案时段温度值
     *
     * @param pns
     */
    public void readPustParameter(List<Integer> pns) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        for (Integer pn : pns) {
            struct.addDataField(new RunaFrameSequence.DataUnit(pn, 210, new byte[]{3, 1, 2, 3}));
        }

        setHaveResult(true);
    }

    /**
     * 读周模式日方案选择
     *
     * @param pns
     */
    public void readPuwdssParameter(List<Integer> pns) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        for (Integer pn : pns) {
            struct.addDataField(new RunaFrameSequence.DataUnit(pn, 211, null));
        }

        setHaveResult(true);
    }

    /**
     * 读自定义节假日方案
     *
     * @param pns
     */
    public void readPudhssParameter(List<Integer> pns) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        for (Integer pn : pns) {
            struct.addDataField(new RunaFrameSequence.DataUnit(pn, 212, new byte[]{8, 1, 2, 3, 4, 5, 6, 7, 8}));
        }

        setHaveResult(true);
    }

    /**
     * 读PID
     *
     * @param pn
     */
    public void readPidParameter(int pn) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 213, null));

        setHaveResult(true);
    }

    /**
     * 读开度限值
     *
     * @param pn
     */
    public void readPuolParameter(int pn) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 215, null));

        setHaveResult(true);
    }

    /**
     * 读时段控制模式
     *
     * @param pn
     */
    public void readTimeFrameControl(int pn) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 210, new byte[]{3, 1, 2, 3}));
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 211, null));
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 212, new byte[]{8, 1, 2, 3, 4, 5, 6, 7, 8}));
        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 216, null));

        setHaveResult(true);
    }

    /**
     * 读单元调控策略
     *
     * @param pn
     */
    public void readPuasParameter(int pn) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));

        struct.addDataField(new RunaFrameSequence.DataUnit(pn, 216, null));

        setHaveResult(true);
    }

    /**
     * 读终端版本
     *
     */
    public void readTerminalVersion() {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ReqTerminalConfig);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 1, null));
        setHaveResult(true);
    }

    /**
     * 读抄表周期
     *
     */
    public void readMeterReadingCycleParameter() {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.QueryParam);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 191, null));
        setHaveResult(true);
    }

    /* -------------------- 控制命令 -------------------- */

    /**
     * 校时
     */
    public void timing(Date date) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ControlCommand);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 0, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 31, TerminalCalendarClock.getInstance(date).toBytes()));

        setHaveResult(true);
    }

    /**
     * 删除测点档案
     */
    public void fmuRecordClear() {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ControlCommand);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 0, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 53, new byte[]{0}));

        setHaveResult(true);
    }

    /**
     * 立即定时抄
     */
    public void immediatelyRead() {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ControlCommand);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 0, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 51, new byte[]{0}));

        setHaveResult(true);
    }

    /**
     * 户通断写阀门锁 —— afn05Fn202
     *
     * @param valveLock
     */
    public void houseOnOffWriteValveLock(Map<Integer, ValveLock> valveLock) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ControlCommand);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        for (Map.Entry<Integer, ValveLock> entry : valveLock.entrySet()) {
            struct.addDataField(new RunaFrameSequence.DataUnit(entry.getKey(), 202, entry.getValue().getBytes()));
        }

        setHaveResult(true);
    }

    /**
     * 户通断写温度锁 —— afn05Fn203
     *
     * @param temperatureLock
     */
    public void houseOnOffWriteTempLock(Map<Integer, TemperatureLock> temperatureLock) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ControlCommand);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        for (Map.Entry<Integer, TemperatureLock> entry : temperatureLock.entrySet()) {
            struct.addDataField(new RunaFrameSequence.DataUnit(entry.getKey(), 203, entry.getValue().getBytes()));
        }

        setHaveResult(true);
    }

    /**
     * 户通断写温度范围
     *
     * @param temperatureRange
     */
    public void houseOnOffWriteTempRange(Map<Integer, TemperatureRange> temperatureRange) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ControlCommand);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        for (Map.Entry<Integer, TemperatureRange> entry : temperatureRange.entrySet()) {
            struct.addDataField(new RunaFrameSequence.DataUnit(entry.getKey(), 204, entry.getValue().getBytes()));
        }

        setHaveResult(true);
    }

    public void houseOnOffWriteTempComp(int index, TemperatureCompensation compensation) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.ControlCommand);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(index, 207, compensation.getBytes()));

        setHaveResult(true);
    }

    /* ------------------ 请求实时数据（I类） ---------------- */

    /**
     * 读取GPRS
     */
    public void readGPRSState() {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.RequestDataOne);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 14, null));

        setHaveResult(true);
    }


    /**
     * 读热表数据
     *
     * @param pns
     */
    public void heatMeterData(List<Integer> pns) {
        heatMeterData(pns, 174);
    }


    public void heatMeterData(List<Integer> pns, int fn) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.RequestDataOne);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        for (int pn : pns) {
            struct.addDataField(new RunaFrameSequence.DataUnit(pn, fn, null));
        }
        setHaveResult(true);
    }


    public static void main(String[] args) {

        WkxValveRequestData wkxValveRequestData = new WkxValveRequestData();
        byte[] hex = wkxValveRequestData.readWkxValve("02407027");

        RunaConcenRequestData requestData = new RunaConcenRequestData("244800269");

        for (int i = 1; i <= 4; i++) {
            requestData.transparentForwarding(i, "2400", "E", 2, 20, hex);
            System.out.println(ByteUtil.byteToHexString(requestData.getData()));
        }



    }


    /**
     * 读阀门数据
     *
     * @param pns
     */
    public void valveData(List<Integer> pns) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.RequestDataOne);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        for (int pn : pns) {
            struct.addDataField(new RunaFrameSequence.DataUnit(pn, 200, null));
        }
        setHaveResult(true);
    }

    /**
     * 读公建单元数据
     *
     * @param pns
     */
    public void publicUnitData(List<Integer> pns) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.RequestDataOne);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        for (int pn : pns) {
            struct.addDataField(new RunaFrameSequence.DataUnit(pn, 176, null));
        }
        setHaveResult(true);
    }

    /**
     * 读测温面板数据
     *
     * @param pns
     */
    public void measurTemperaturePanelData(List<Integer> pns) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.RequestDataOne);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        for (int pn : pns) {
            struct.addDataField(new RunaFrameSequence.DataUnit(pn, 201, null));
        }
        setHaveResult(true);
    }

    /**
     * 组合指令——（单元调控装置）
     *
     * @param mPn
     * @param vPn
     */
    public void meterPublicUnitData(int mPn, int vPn) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.RequestDataOne);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(mPn, 174, null));
        struct.addDataField(new RunaFrameSequence.DataUnit(vPn, 176, null));
        setHaveResult(true);
    }

    public void extendData(int code) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.RequestDataOne);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 248, new byte[]{2, 0, (byte) code, 0}));
        setHaveResult(true);
    }

    /*------------------- 数据转发 ------------------*/

    /**
     * 透明转发
     *
     * @param data
     */
    public void transparentForwarding(int port, String baud, String parity, int msgTimeout, int byteTimeout, byte[] data) {
        struct = new RunaICStruct();
        struct.setArea(new RunaFrameSequence.Area(address));
        struct.setControl(new RunaFrameSequence.Control(0, 1, 0, 0, AppFunCode.prmFunCode.PRM1_RequestDataOne));
        struct.setAfn(AppFunCode.rnicAFN.DataForward);
        struct.setSeq(new RunaFrameSequence.Seq(0, 1, 1, 1, 0));
        int size = data.length & 0xffff;
        int ctrl = 3;
        switch (baud) {
            case "300":
                break;
            case "600":
                ctrl |= 0b0010_0000;
                break;
            case "1200":
                ctrl |= 0b0100_0000;
                break;
            case "2400":
                ctrl |= 0b0110_0000;
                break;
            case "4800":
                ctrl |= 0b1000_0000;
                break;
            case "7200":
                ctrl |= 0b1010_0000;
                break;
            case "9600":
                ctrl |= 0b1100_0000;
                break;
            case "19200":
                ctrl |= 0b1110_0000;
                break;
        }
        switch (parity) {
            case "O":
                ctrl |= 0b1100;
                break;
            case "E":
                ctrl |= 0b1000;
                break;
            case "N":
                break;
        }
        byte[] bs = new byte[]{(byte) port, (byte) ctrl,
                (byte) (msgTimeout | 0x80), (byte) (byteTimeout & 0x7f),
                (byte) size, (byte) (size >> 8)};
        byte[] password = new byte[]{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
        struct.addDataField(new RunaFrameSequence.DataUnit(0, 1, ByteUtil.merge(bs, data, password)));
        setHaveResult(true);
    }


    @Override
    public boolean check(IResponseData data) {
        if (data instanceof RunaConcenAffirmDeny) {
            RunaConcenAffirmDeny affirmDeny = (RunaConcenAffirmDeny) data;
            return affirmDeny.getAddress().equals(address);
        } else if (data instanceof RunaConcenResponseData) {
            RunaConcenResponseData responseData = (RunaConcenResponseData) data;
            return responseData.getAddress().equals(address)
                    && responseData.getCommand().equals(struct.getAfn());
        }
        return false;
    }

    @Override
    public byte[] getData() {
        return struct.getBuffer();
    }

    public void readHyMeter(String serial, int port) {
        HyMeterRequestData requestData = new HyMeterRequestData();
        byte[] hex = requestData.readHyMeter(serial);
        transparentForwarding(port, "2400", "E", 2, 20, hex);
    }

    public void readWkxValve(String serial, int port) {
        WkxValveRequestData wkxValveRequestData = new WkxValveRequestData();
        byte[] hex = wkxValveRequestData.readWkxValve(serial);
        transparentForwarding(port, "2400", "E", 2, 20, hex);
    }

    public void setWkxValveOpen(String serial, int port, Integer opening, boolean ifLock) {
        WkxValveRequestData wkxValveRequestData = new WkxValveRequestData();
        byte[] hex = wkxValveRequestData.setWkxValveOpen(serial, opening, ifLock);
        transparentForwarding(port, "2400", "E", 2, 20, hex);
    }

    public void readKtValve(String serial, Integer port) {
        KtValveRequestData ktValveRequestData = new KtValveRequestData();
        byte[] hex = ktValveRequestData.readKtValve(serial);
        transparentForwarding(port, "2400", "E", 2, 20, hex);
    }

    public void setKtValveOpen(String serial, int port, Integer opening, boolean ifLock) {
        KtValveRequestData ktValveRequestData = new KtValveRequestData();
        byte[] hex = ktValveRequestData.setKtValveOpen(serial, opening, ifLock);
        transparentForwarding(port, "2400", "E", 2, 20, hex);
    }

    public void readPsValve(String serial, Integer port) {
        PsValveRequestData requestData = new PsValveRequestData();
        byte[] hex = requestData.readValve(serial);
        transparentForwarding(port, "2400", "E", 2, 20, hex);
    }

    public void setPsValveOpen(String serial, int port, Integer opening, boolean ifLock) {
        PsValveRequestData requestData = new PsValveRequestData();
        byte[] hex = requestData.setValveOpen(serial, opening, ifLock);
        transparentForwarding(port, "2400", "E", 2, 20, hex);
    }


}
